package com.itheima.appserver.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.dubbo.config.annotation.Reference;
import com.itheima.appserver.excepiton.BusinessException;
import com.itheima.appserver.excepiton.ErrorResult;
import com.itheima.appserver.interceptor.UserThreadLocal;
import com.itheima.commons.constants.Constants;
import com.itheima.commons.pojo.domain.*;
import com.itheima.commons.pojo.mongo.UserLike;
import com.itheima.commons.pojo.mongo.Visitors;
import com.itheima.commons.vo.reception.*;
import com.itheima.dubbo.interfaces.*;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author yaohu
 * @date 2021/12/12
 * @Version 1.0
 * @describe
 */
@Service
public class MyCenterService {

    @Reference
    private UserInfoApi userInfoApi;

    @Reference
    private UserLikeApi userLikeApi;

    @Reference
    private RecommendUserApi recommendUserApi;

    @Reference
    private VisitorsApi visitorsApi;

    @Reference
    private SettingsApi settingsApi;

    @Reference
    private QuestionApi questionApi;

    @Reference
    private BlackListApi blackListApi;

    @Reference
    private UserApi userApi;

    @Autowired
    private IMService imService;

    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 根据用户id查询用户信息
     *
     * @param userId 用户id，如果为空，表示查询当前登录人的信息
     * @return
     */
    public UserInfoVo queryUserInfoByUserId(Long userId) {

        UserInfo userInfo = userInfoApi.findUserInfoByUserId(ObjectUtil.isNull(userId) ? UserThreadLocal.getUserId() : userId);

        UserInfoVo userInfoVo = new UserInfoVo();
        // 用户ID
        userInfoVo.setId(userInfo.getUserId());
        userInfoVo.setAvatar(userInfo.getLogo());
        userInfoVo.setNickname(userInfo.getNickName());
        userInfoVo.setBirthday(userInfo.getBirthday());
        userInfoVo.setAge(userInfo.getAge().toString());
        userInfoVo.setGender(userInfo.getSex() == 1 ? "man" : "woman");
        userInfoVo.setCity(userInfo.getCity());
        userInfoVo.setEducation(userInfo.getEdu());
        userInfoVo.setIncome(userInfo.getIncome());
        userInfoVo.setProfession(userInfo.getIndustry());
        userInfoVo.setMarriage("已婚".equals(userInfo.getMarriage()) ? 1 : 0);

        return userInfoVo;
    }

    /**
     * 互相喜欢，喜欢，粉丝 - 统计
     *
     * @return
     */
    public CountsVo queryCounts() {
        CountsVo countsVo = new CountsVo();

        // 查询互相喜欢数
        Long mutualLikeCount = userLikeApi.queryMutualLikeCount(UserThreadLocal.getUserId());
        countsVo.setEachLoveCount(mutualLikeCount);

        // 查询我喜欢的人数量
        // 先查询redis 如果redis没有 在查询mongodb
        Long likeCount = redisTemplate.opsForSet().size(Constants.USER_LIKE_KEY + UserThreadLocal.getUserId());
        if (likeCount == 0) {
            Long count = userLikeApi.queryLikeCount(UserThreadLocal.getUserId());
            countsVo.setLoveCount(count);
        } else {
            countsVo.setLoveCount(likeCount);
        }

        // 查询粉丝数
        Long fanCount = userLikeApi.queryFanCount(UserThreadLocal.getUserId());
        countsVo.setFanCount(fanCount);
        // 返回vo对象
        return countsVo;
    }

    /**
     * 互相关注、我关注、粉丝、谁看过我 - 翻页列表
     *
     * @param type     1 互相关注 2 我喜欢 3 粉丝 4 谁看过我
     * @param page
     * @param pageSize
     * @param nickname
     * @return
     */
    public PageResult queryLikeList(Integer type, Integer page, Integer pageSize, String nickname) {
        // 分页条件查询userLike结果集
        List<UserLike> userLikes = new ArrayList<>();
        // 获取结果集关键字段集合
        List<Long> userIds = new ArrayList<>();
        switch (type) {
            // 互相喜欢
            case 1: {
                userLikes = userLikeApi.queryMutualLikeList(UserThreadLocal.getUserId(), page, pageSize);
                userIds = CollUtil.getFieldValues(userLikes, "userId", Long.class);
                break;
            }
            // 喜欢
            case 2: {
                userLikes = userLikeApi.queryLikeList(UserThreadLocal.getUserId(), page, pageSize);
                userIds = CollUtil.getFieldValues(userLikes, "likeUserId", Long.class);
                break;
            }
            // 粉丝
            case 3: {
                userLikes = userLikeApi.queryFanList(UserThreadLocal.getUserId(), page, pageSize);
                userIds = CollUtil.getFieldValues(userLikes, "likeUserId", Long.class);
                break;
            }
            // 来访列表
            case 4: {
                List<Visitors> visitors = visitorsApi.topVisitor(UserThreadLocal.getUserId(), page, pageSize);
                userIds = CollUtil.getFieldValues(visitors, "visitorUserId", Long.class);

                // 记录这次查询的时间
                redisTemplate.opsForValue().set(Constants.VISITORS_USER_KEY + UserThreadLocal.getUserId(),
                        Convert.toStr(System.currentTimeMillis()));
                break;
            }
            default: {
                throw new BusinessException(ErrorResult.typeError());
            }
        }

        Map<Long, UserInfo> userInfoMap = userInfoApi.findUserInfoByUserIds(userIds);

        // 组合vo对象
        ArrayList<UserLikeListVo> userLikeListVos = new ArrayList<>();
        for (UserInfo info : userInfoMap.values()) {
            UserLikeListVo userLikeListVo = new UserLikeListVo();
            userLikeListVo.setId(info.getUserId());
            userLikeListVo.setAvatar(info.getLogo());
            userLikeListVo.setNickname(info.getNickName());
            userLikeListVo.setGender(info.getSex() == 1 ? "man" : "woman");
            userLikeListVo.setAge(info.getAge());
            userLikeListVo.setCity(info.getCity());
            userLikeListVo.setEducation(info.getEdu());
            userLikeListVo.setMarriage("已婚".equals(info.getMarriage()) ? 1 : 0);
            // 查询推荐缘分值
            Long score = recommendUserApi.queryScoreByUserId(UserThreadLocal.getUserId(), info.getUserId());
            if (ObjectUtil.isNull(score)) {
                userLikeListVo.setMatchRate(60);
            } else {
                userLikeListVo.setMatchRate(Convert.toInt(score));
            }
            // 查询是否喜欢
            userLikeListVo.setAlreadyLove(userLikeApi.isAlreadyLove(UserThreadLocal.getUserId(), info.getUserId()));
            userLikeListVos.add(userLikeListVo);
        }
        return new PageResult(page, pageSize, 0L, userLikeListVos);
    }

    /**
     * 取消喜欢
     *
     * @param userId
     * @return
     */
    public void disLike(Long userId) {
        // 1.判断两人是否为相互喜欢
        if (userLikeApi.isMutualLike(UserThreadLocal.getUserId(), userId)) {
            // 2.解除好友关系
            imService.removeContactUser(userId);
        }
        // 3.删除MongoDB中的数据
        userLikeApi.notLikeUser(UserThreadLocal.getUserId(), userId);
        // 4.删除redis中的数据
        redisTemplate.opsForSet().remove(Constants.USER_LIKE_KEY + UserThreadLocal.getUserId(), userId.toString());
    }

    /**
     * 关注粉丝
     *
     * @param userId
     * @return
     */
    public void likeFan(Long userId) {
        // 1.添加粉丝到MongoDB
        UserLike userLike = new UserLike();
        userLike.setId(new ObjectId());
        userLike.setUserId(UserThreadLocal.getUserId());
        userLike.setLikeUserId(userId);
        userLike.setCreated(System.currentTimeMillis());
        userLikeApi.likeUser(userLike);
        // 2.添加到redis中
        redisTemplate.opsForSet().add(Constants.USER_LIKE_KEY + UserThreadLocal.getUserId(), userId.toString());
        // 3.添加好友
        imService.contactUser(userId);
    }

    /**
     * 修改用户信息
     *
     * @param nickname   昵称
     * @param birthday   生日 1990-01-01
     * @param gender     性别 man woman
     * @param city       城市
     * @param education  学历
     * @param income     月收入
     * @param profession 行业
     * @param marriage   婚姻状态（0未婚，1已婚）
     * @return
     */
    public void updateInfo(String nickname, String birthday, String gender, String city, String education, String income, String profession, Integer marriage) {
        // 1.查询自己的userInfo信息
        UserInfo userInfo = userInfoApi.findUserInfoByUserId(UserThreadLocal.getUserId());
        // 2.修改信息
        userInfo.setNickName(nickname);
        userInfo.setBirthday(birthday);
        userInfo.setSex(gender);
        userInfo.setCity(city);
        userInfo.setEdu(education);
        userInfo.setIncome(income);
        userInfo.setIndustry(profession);
        userInfo.setMarriage(marriage == 0 ? "未婚" : "已婚");
        // 3.保存到数据库中
        userInfoApi.addUserInfo(userInfo);
    }

    /**
     * 用户通用设置 - 读取
     *
     * @return
     */
    public SettingsVo findSettings() {
        // 1.查询通用设置表
        Settings settings = settingsApi.querySettings(UserThreadLocal.getUserId());
        // 2.查询用户问题表
        Question question = questionApi.findQuestionByUserId(UserThreadLocal.getUserId());
        // 3.拼凑vo
        SettingsVo settingsVo = new SettingsVo();

        if (ObjectUtil.isNull(settings)) {
            settingsVo.setId(0);
            settingsVo.setLikeNotification(false);
            settingsVo.setPinglunNotification(false);
            settingsVo.setGonggaoNotification(false);
        } else {
            settingsVo.setId(Convert.toInt(settings.getId()));
            settingsVo.setLikeNotification(settings.isLikeNotification());
            settingsVo.setPinglunNotification(settings.isPinglunNotification());
            settingsVo.setGonggaoNotification(settings.isGonggaoNotification());
        }

        if (ObjectUtil.isNull(question)) {
            settingsVo.setStrangerQuestion("");
        } else {
            settingsVo.setStrangerQuestion(question.getTxt());
        }

        settingsVo.setPhone(UserThreadLocal.getUserMobile());

        return settingsVo;
    }

    /**
     * 保存/更新通用设置
     *
     * @param likeNotification    是否推送喜欢通知
     * @param pinglunNotification 是否推送评论通知
     * @param gonggaoNotification 是否推送公告通知
     * @return
     */
    public void addSettings(boolean likeNotification, boolean pinglunNotification, boolean gonggaoNotification) {
        // 1.查询数据库通用设置表
        Settings settings = settingsApi.querySettings(UserThreadLocal.getUserId());

        // 2.判断是否为空
        if (ObjectUtil.isNull(settings)) {
            // 为空 新增
            settings = new Settings();
            settings.setUserId(UserThreadLocal.getUserId());
            settings.setCreated(new Date());
        }
        // 不为空 更新
        settings.setLikeNotification(likeNotification);
        settings.setPinglunNotification(pinglunNotification);
        settings.setGonggaoNotification(gonggaoNotification);
        settings.setUpdated(new Date());

        // 3.添加/修改到数据库中
        settingsApi.addSettings(settings);
    }

    /**
     * 修改陌生人问题
     *
     * @param content
     */
    public void updateQuestion(String content) {
        // 1.查询数据库问题表
        Question question = questionApi.findQuestionByUserId(UserThreadLocal.getUserId());

        // 2.判断问题是否存在
        if (ObjectUtil.isNull(question)) {
            // 不存在 新增
            question = new Question();
            question.setUserId(UserThreadLocal.getUserId());
            question.setCreated(new Date());
        }
        // 存在 更新
        question.setTxt(content);
        question.setUpdated(new Date());

        // 3.保存到数据库中
        questionApi.saveQuestion(question);
    }

    /**
     * 分页查询黑名单列表
     *
     * @param page
     * @param pagesize
     * @return
     */
    public PageResult queryBlackList(Integer page, Integer pagesize) {
        // 1.查询Mysql数据库的黑名单
        List<BlackList> blackList = blackListApi.queryBlackListByUserId(UserThreadLocal.getUserId(), page, pagesize);
        // 2.判断查询结果是否为空
        if (ObjectUtil.isEmpty(blackList)) {
            // 为空 直接返回
            return new PageResult(page, pagesize, 0L, Collections.emptyList());
        }
        // 3.不为空 获取黑名单用户id
        List<Long> blackUserIds = CollUtil.getFieldValues(blackList, "blackUserId", Long.class);
        // 4.根据id集合查询黑名单用户信息
        Map<Long, UserInfo> userInfoMap = userInfoApi.findUserInfoByUserIds(blackUserIds);
        // 5.拼凑vo
        List<BlackListVo> blackListVoList = new ArrayList<>();

        for (UserInfo info : userInfoMap.values()) {
            BlackListVo blackListVo = new BlackListVo();

            blackListVo.setId(Convert.toInt(info.getId()));
            blackListVo.setAvatar(info.getLogo());
            blackListVo.setNickname(info.getNickName());
            blackListVo.setGender(info.getSex() == 1 ? "man" : "woman");
            blackListVo.setAge(info.getAge());

            blackListVoList.add(blackListVo);
        }
        return new PageResult(page, pagesize, 0L, blackListVoList);
    }

    /**
     * 黑名单 - 移除
     *
     * @param userId
     */
    public void removeBlackList(Long userId) {
        // 1.删除数据库中blackUserId为userId的记录
        blackListApi.removeBlackList(UserThreadLocal.getUserId(), userId);
    }

    /**
     * 修改手机号 - 2 校验验证码
     *
     * @param verificationCode
     * @return
     */
    public Boolean checkVerificationCode(String verificationCode) {
        // 判断这个手机号码是否是合法的
        if (!Validator.isMobile(UserThreadLocal.getUserMobile())) {
            // 如果不合法直接抛出异常
            throw new BusinessException(ErrorResult.phoneNumError());
        }
        // 判断验证码是否一致
        String code = redisTemplate.opsForValue().get(Constants.SMS_CODE + UserThreadLocal.getUserMobile());
        if (null == code || null == verificationCode || !code.equals(verificationCode)) {
            throw new BusinessException(ErrorResult.verificationCodeError());
        }
        // 删除验证码
        redisTemplate.delete(Constants.SMS_CODE + UserThreadLocal.getUserMobile());
        return true;
    }

    /**
     * 修改手机号 - 3 保存
     *
     * @param phone 新手机号
     */
    public void savePhone(String phone) {
        // 先判断新手机号码是否已经被占用
        User newPhoneUser = userApi.findUserByPhoneNum(phone);
        if (ObjectUtil.isNotEmpty(newPhoneUser)) {
            throw new BusinessException(ErrorResult.newPhoneNumISAlreadyOccupied());
        }
        // 更新数据库中信息
        userApi.updatePhone(UserThreadLocal.getUserMobile(), phone);
    }
}
